﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OAuthApp.Data;
using OAuthApp.Tenant;
using Swashbuckle.AspNetCore.Annotations;
using System;
using System.Linq;
using System.Security.Claims;

namespace OAuthApp.Services
{
    public class ApiRequestLoggingAttribute : IActionFilter
    {
        readonly IWebHostEnvironment _webHostEnvironment;
        readonly AppDbContext _context;

        public ApiRequestLoggingAttribute(
            IWebHostEnvironment webHostEnvironment,
            AppDbContext context)
        {
            _webHostEnvironment = webHostEnvironment;
            _context = context;
        }

        public ApiRequestLoggingAttribute()
        {

        }

        AppLog CurrentRequestLog { get; set; }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (string.IsNullOrWhiteSpace(CurrentRequestLog.AppKey))
            {
                return;
            }

            object result = null;

            if (context.Result is ObjectResult)
            {
                result = (context.Result as ObjectResult).Value;
            }

            else if (context.Result is JsonResult)
            {
                result = (context.Result as JsonResult).Value;
            }

            CurrentRequestLog.ReqEnd = DateTime.Now;

            if (result != null)
            {
                CurrentRequestLog.ResData = JsonConvert.SerializeObject(result);
            }

            try
            {
                _context.AppLogs.Add(CurrentRequestLog);

                _context.SaveChanges();
            }
            catch { }
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            CurrentRequestLog = new AppLog();

            CurrentRequestLog.ReqData = JsonConvert.SerializeObject(context.ActionArguments);

            CurrentRequestLog.ReqStart = DateTime.Now;

            CurrentRequestLog.ReqPath = context.HttpContext.Request.Path;

            CurrentRequestLog.UserAgent = context.HttpContext.Request.Headers["User-Agent"];

            var actionDesc = context.ActionDescriptor as ControllerActionDescriptor;

            var operationAttr = actionDesc.MethodInfo.
                GetCustomAttributes(typeof(SwaggerOperationAttribute), false)
                .FirstOrDefault() as SwaggerOperationAttribute;

            if(operationAttr!=null)
            {
                CurrentRequestLog.OperationId = operationAttr.OperationId;
            }

            if (context.HttpContext.User.Identity.IsAuthenticated)
            {
                CurrentRequestLog.UserID =
                    context.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;

                CurrentRequestLog.UserGroup =
                    context.HttpContext.User.FindFirst(ClaimTypes.GroupSid).Value;

                var cient_id_string = context.HttpContext.User.FindFirst(TenantClaimTypes.ClientId).Value;

                if (long.TryParse(cient_id_string, out long client_id))
                {
                    CurrentRequestLog.AppKey = _context.Apps.Where(x => x.ID == client_id)
                            .Select(x => x.AppKey).FirstOrDefault();
                }
            }

            else
            {
                var _appId = 0L;

                if (context.ActionArguments.ContainsKey("appId"))
                {
                    var appId = context.ActionArguments["appId"];

                    if (appId != null)
                    {
                        long.TryParse(appId.ToString(), out _appId);

                    }

                    else if (!string.IsNullOrWhiteSpace(CurrentRequestLog.ReqData))
                    {
                        JToken reqData = null;
                        try
                        {
                            reqData = JObject.Parse(CurrentRequestLog.ReqData)["value"];
                        }
                        catch { }

                        if (reqData.Value<string>("AppID") != null)
                        {
                            long.TryParse(reqData.Value<string>("AppID").ToString(),
                            out _appId);
                        }
                    }
                }
               
                if (_appId != 0)
                {
                    CurrentRequestLog.AppKey = _context.Apps.Where(x => x.ID == _appId)
                               .Select(x => x.AppKey).FirstOrDefault();
                    CurrentRequestLog.UserID = "";
                    CurrentRequestLog.UserGroup = UserDataGroups.Client;
                }
            }
        }
    }
}
